#pragma once

#include "application/vehicle/vehicle_service.h"
#include "application/map/map_application_service.h"
#include "application/pathfinding/multi_agent_solver.h"
#include "concurrent_combination_solver.h"
#include "kernel/interfaces/ILogger.h"
#include <QDateTime>
#include <QFutureWatcher>
#include <QObject>
#include <QHash>
#include <QTimer>
#include <QList>
#include <QSet>
#include <QString>
#include <functional>
#include <memory>
#include <vector>

namespace application {
namespace dispatcher {

enum class TaskFunction { FuncNormal, FuncMove, FuncLift };
enum class MoveFunctionStatus { MoveOk, MoveError, MoveNoIdle, MoveCharging, MoveNeedPassFloor };

struct TaskPublishHandle {
    TaskFunction func{TaskFunction::FuncMove};
    int agvNumber{-1};
    MoveFunctionStatus moveStatus{MoveFunctionStatus::MoveOk};
};

class RouteDispatcher : public QObject {
    Q_OBJECT

public:
    explicit RouteDispatcher(const QString& mapName, int floor,
                             std::shared_ptr<vehicle::VehicleService> vehicleService,
                             std::shared_ptr<MapApplicationService> mapService,
                             std::shared_ptr<kernel::ILogger> logger,
                             QObject* parent = nullptr);
    ~RouteDispatcher() override = default;

    void init();
    void solveAndPublishNow();
    void cancelPendingForAgv(int agvNumber, const QString& reason = QString());

    // Submit a station task from server (single request)
    TaskPublishHandle stationTaskFromServer(const QString& station,
                                            const QString& operation = QString(),
                                            std::function<void()> arriveCallback = {});

    // Submit a station task for a specific AGV
    TaskPublishHandle stationTaskFromServer(int agvNumber,
                                            const QString& station,
                                            const QString& operation = QString(),
                                            std::function<void()> arriveCallback = {});

    void setDispatchCallback(std::function<void(int, const QList<QString>&)> cb);
    void setSolveFailureCallback(std::function<void(const QString&)> cb) { m_solveFailureCallback = std::move(cb); }

    /**
     * @brief 重新调度指定AGV的任务
     *
     * 将该AGV的调度目标重新加入pending队列，触发正常求解流程。
     * 不取消当前任务，按正常冻结机制处理。
     *
     * @param agvNumber AGV编号
     * @return true 成功加入队列, false 无法获取目标或AGV不存在
     */
    bool rescheduleAgvTask(int agvNumber);

    /**
     * @brief 标记AGV为等待状态（因目标冲突）
     * @param agvNumber AGV编号
     * @param targetGoal 真正想去的目标站点
     */
    void markAgvAsWaiting(int agvNumber, const QString& targetGoal);

    // 并发求解配置
    void setEnableConcurrentSolving(bool enable) { m_enableConcurrentSolving = enable; }
    bool isEnableConcurrentSolving() const { return m_enableConcurrentSolving; }
    void setMaxConcurrentCandidates(int max) { m_maxConcurrentCandidates = max; }

signals:
    void sigFindPathFailed();
    void sigFindPathSuccess();

private slots:
    void slotReqPathSolveTimer();
    void slotPublishMoveTask();
    void onVehicleStatusChanged(int agvNumber);
    void slotCheckNavigationState();

private:
    QString m_mapName; int m_floor{ -1 };
    std::shared_ptr<vehicle::VehicleService> m_vehicleService;
    std::shared_ptr<MapApplicationService> m_mapService;
    std::shared_ptr<kernel::ILogger> m_logger;
    // Timers intentionally not started: scheduling is demand-driven
    QTimer m_solveTimer;
    QTimer m_publishTimer;

    struct PendingRequest {
        int agvNumber;
        QString start;
        QString goal;
        QString operation;
        std::function<void()> callback;
        qint64 requestedAt{0};  // ms since epoch for priority
    };
    std::vector<PendingRequest> m_pending;

    // Planned routes per AGV (queue of station segments)
	    QHash<int, QList<QList<QString>>> m_plannedSegments;
	    QHash<int, QString> m_agvOperations;  // Store operation for each AGV's final destination
	    QHash<int, QString> m_lastSegmentGoal;  // Track last dispatched segment goal per AGV
	    QHash<int, QString> m_taskGoalCache;    // Cache last task-layer goal per AGV for recovery/continuation
	    QHash<QString, int> m_specialStationWhiteList;
	    std::function<void(int, const QList<QString>&)> m_dispatchCallback;

    // Backoff control when currentStation is missing
    QHash<int, QDateTime> m_emptyStationRetryAt;  // covers empty current + fallback align
    static constexpr int EmptyStationBackoffMs{2000};

    // 并发求解配置
    bool m_enableConcurrentSolving{true};     // 默认启用并发求解
    int m_maxConcurrentCandidates{5};         // 最多尝试5种组合
    bool m_concurrentSolveRunning{false};
    QFutureWatcher<ConcurrentCombinationSolver::SolveResult> m_concurrentWatcher;
    std::vector<PendingRequest> m_activeSolveRequests;  // 当前并发求解使用的请求快照
    std::function<void(const QString&)> m_solveFailureCallback;

    bool isAgvOnThisMap(int agvNumber) const;
    bool isAgvChargingOrInChargeArea(int agvNumber) const;
    int selectNearestIdleAgv(const QString& goal) const;
    void enqueuePlan(const std::vector<pathfinding::AgentPlan>& plans);
    struct StartResolution {
        QString station;
        bool usedLastStation{false};    // true when fallback to lastStation was used
        bool usedTargetAsStart{false};  // true when target/next waypoint used as start
    };
    StartResolution resolveStartStationWithMeta(const kernel::agv::AgvEntity* agv) const;
    QString resolveStartStation(const kernel::agv::AgvEntity* agv) const {
        return resolveStartStationWithMeta(agv).station;
    }

    // Lock/wait structure (ported skeleton from third-party)
    enum class LockStatus { Pending, Locking, UnLock, Finished };
    struct LockTask {
        int awaited;
        QString unlockStationFrom;
        QString unlockStation;
        int waiter;
        LockStatus status{LockStatus::Pending};
        int stationsIndex{0};
    };
    struct LockList { int agvNum; QList<LockTask> tasks; };
    QList<LockList*> m_lockLists;               // route_index -> LockList*
    QHash<int, LockList*> m_lockListHash;       // waiter agv -> LockList*
    void addWaitTask(int routeIndex, int awaited, const QString& unlockFrom, const QString& unlockTo,
                     int waiter, int stationIndex, LockStatus initialStatus = LockStatus::Pending);
    void onAreaExited(int agvId, const QString& areaId);
    void clearLocksForAgv(int agvNumber);
    void resetLocksForAgvs(const QSet<int>& agvs);
    static QString lockStatusToString(LockStatus status);
    QString makeLockBlockLogKey(const LockTask& task, int waiterAgv) const;
    void clearLockBlockLogKey(const LockTask& task, int waiterAgv);
    void processWaitingAgvs();
    QSet<QString> collectBlockAreasForPath(const QStringList& path) const;
    void reserveBlockAreas(int agvNumber, const QSet<QString>& areaIds);
    void releaseBlockAreasForAgv(int agvNumber);

    // Helpers for third-party-consistent locking
    void updateLocks();
    bool hasBlockingLock(int waiterAgv, int upcomingSegmentIndex, QSet<int>* blockingAwaited = nullptr);
    bool detectMutualLock(int waiterAgv, const QSet<int>& blockingAwaited, QSet<int>& involvedAgvs) const;
    void resolveDeadlock(const QSet<int>& involvedAgvs);
    void finalizeLocksForWaiter(int waiterAgv);
    QSet<QString> m_emittedLockBlockLogs;  // 已输出的阻塞日志，避免重复刷屏

    // Segment cursor tracking
    QHash<int, int> m_segmentCursor;
    int nextSegmentIndex(int agvNumber) const;
    void advanceSegmentCursor(int agvNumber, int delta = 1);
    QString currentPlanGoal(int agvNumber) const;

    void ensurePublishTimerActive();
    void stopPublishTimerIfIdle();
    bool hasPendingSegments() const;
    void schedulePublishAttempt();
    void scheduleSolveAttempt();
    void onConcurrentSolveFinished();

    // AGVs frozen from dispatch while waiting for solve (e.g., start derived from future target)
    QSet<int> m_solveFreezeAgvs;

    // ========== 拯救功能相关 ==========

    // 等待车跟踪（因目标冲突被设为 start==goal 的AGV）
    struct WaitingAgvInfo {
        int agvNumber;
        QString targetGoal;     // 真正想去的目标
        QDateTime waitingSince; // 开始等待时间
    };
    QHash<int, WaitingAgvInfo> m_waitingAgvs;  // AGV编号 -> 等待信息

    // 检查是否有等待车需要重新调度（当某站点被释放时）
    void checkAndRescheduleWaitingAgvs(const QString& releasedStation);

    // Block area reservations (className == BlockArea)
    QHash<QString, int> m_blockAreaReservations;  // areaId -> agv
    QHash<int, QSet<QString>> m_agvReservedBlockAreas;  // agv -> areaIds

    // 已下发但未确认导航状态的AGV跟踪
    struct DispatchedSegmentInfo {
        int agvNumber;
        QStringList segment;        // 下发的段
        QDateTime dispatchedAt;     // 下发时间
        int retryCount{0};          // 重试次数
        static constexpr int MaxRetries = 3;
        static constexpr int TimeoutMs = 5000;  // 5秒超时
    };
    QHash<int, DispatchedSegmentInfo> m_dispatchedPending;
    QTimer m_stateCheckTimer;       // 状态检查定时器（2秒间隔）
};

} // namespace dispatcher
} // namespace application
